package com.mofum.scope.annotation.controller.parser;

import com.mofum.scope.annotation.controller.ServiceColumn;
import com.mofum.scope.annotation.controller.UpdateScope;
import com.mofum.scope.common.annotation.AnnotationParser;
import com.mofum.scope.common.annotation.metadata.controller.MServiceColumn;
import com.mofum.scope.common.annotation.metadata.controller.MUpdateScope;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 增删改操作范围解析器
 *
 * @author yuyang@qxy37.com
 * @since 2019-03-20
 **/
public class UpdateScopeParser<T> implements AnnotationParser<Class<T>, MUpdateScope> {

    public Map<Field, MUpdateScope> parseField(Class<T> tClass) {

        Map<Field, MUpdateScope> map = new HashMap<Field, MUpdateScope>();

        Field[] fields = tClass.getDeclaredFields();

        for (Field field : fields) {

            if (field.isAnnotationPresent(UpdateScope.class)) {

                UpdateScope atColumn = field.getAnnotation(UpdateScope.class);

                map.put(field, parse(atColumn));

            }

        }

        return map;
    }

    public Map<Type, MUpdateScope> parseType(Class<T> tClass) {

        Map<Type, MUpdateScope> map = new HashMap<Type, MUpdateScope>();

        Class<?> clazz = tClass;

        if (clazz.isAnnotationPresent(UpdateScope.class)) {

            UpdateScope atColumn = clazz.getAnnotation(UpdateScope.class);

            map.put(clazz, parse(atColumn));

        }

        return map;
    }

    public Map<Method, MUpdateScope> parseMethod(Class<T> tClass) {

        Map<Method, MUpdateScope> map = new HashMap<Method, MUpdateScope>();

        Method[] methods = tClass.getDeclaredMethods();

        for (Method method : methods) {

            if (method.isAnnotationPresent(UpdateScope.class)) {

                UpdateScope atColumn = method.getAnnotation(UpdateScope.class);

                map.put(method, parse(atColumn));

            }

        }

        return map;
    }

    public Map<Method, List<MUpdateScope>> parseParams(Class<T> tClass) {

        Map<Method, List<MUpdateScope>> map = new HashMap<Method, List<MUpdateScope>>();

        Method[] methods = tClass.getDeclaredMethods();

        for (Method method : methods) {

            List<MUpdateScope> list = new ArrayList<MUpdateScope>();

            Annotation[][] parameterAnnotations = method.getParameterAnnotations();

            for (Annotation[] parameterAnnotation : parameterAnnotations) {
                for (Annotation annotation : parameterAnnotation) {
                    if (annotation instanceof UpdateScope) {
                        UpdateScope atColumn = (UpdateScope) annotation;
                        list.add(parse(atColumn));
                    }
                }
            }

            map.put(method, list);
        }

        return map;
    }

    public MUpdateScope parse(UpdateScope updateScope) {
        MUpdateScope mUpdateScope = new MUpdateScope();
        mUpdateScope.setEnableAuthenticator(updateScope.enableAuthenticator());
        mUpdateScope.setExtractors(updateScope.extractors());
        mUpdateScope.setAuthenticators(updateScope.authenticators());
        mUpdateScope.setEnableExtractor(updateScope.enableExtractor());
        mUpdateScope.setEnableConverter(updateScope.enableConverter());
        mUpdateScope.setConverters(updateScope.converts());
        mUpdateScope.setServiceColumns(updateScope.serviceColumns());
        mUpdateScope.setEnableCustomServiceColumns(updateScope.enableCustomServiceColumns());
        mUpdateScope.setType(updateScope.type());

        ServiceColumn[] serviceColumns = updateScope.columns();
        String[] stringServiceColumns = updateScope.serviceColumns();
        String type = updateScope.type();

        Map<String, MServiceColumn> serviceColumnMap = new HashMap<>();

        if (stringServiceColumns != null) {
            for (int i = 0; i < stringServiceColumns.length; i++) {
                MServiceColumn serviceColumn = new MServiceColumn();
                serviceColumn.setName(stringServiceColumns[i]);
                serviceColumn.setType(type);
                serviceColumnMap.put(stringServiceColumns[i], serviceColumn);
            }
        }

        if (serviceColumns != null) {

            ServiceColumnParser serviceColumnParser = new ServiceColumnParser();
            for (int i = 0; i < serviceColumns.length; i++) {
                MServiceColumn mServiceColumn = serviceColumnParser.parse(serviceColumns[i]);
                serviceColumnMap.put(mServiceColumn.getName(), mServiceColumn);
            }
        }
        MServiceColumn[] res = new MServiceColumn[serviceColumnMap.size()];

        int i = 0;
        for (String key : serviceColumnMap.keySet()) {
            res[i] = serviceColumnMap.get(key);
            i++;
        }
        mUpdateScope.setColumns(res);
        return mUpdateScope;
    }

}